package com.example.rssreader.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.example.rssreader.common.PageResponse;
import com.example.rssreader.dto.AddFeedRequest;
import com.example.rssreader.dto.FeedResponse;
import com.example.rssreader.entity.Article;
import com.example.rssreader.entity.RssFeed;
import com.example.rssreader.mapper.ArticleMapper;
import com.example.rssreader.mapper.RssFeedMapper;
import com.example.rssreader.service.RssFeedService;
import com.example.rssreader.service.RssParserService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * RSS源服务实现类
 * 实现RSS源相关的业务逻辑
 * 
 * @author RSS Reader Team
 * @version 1.0.0
 * @since 2024-01-01
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class RssFeedServiceImpl implements RssFeedService {

    private final RssFeedMapper rssFeedMapper;
    private final ArticleMapper articleMapper;
    private final RssParserService rssParserService;

    /**
     * 添加RSS源
     * 验证URL有效性，解析RSS源信息并保存
     * 
     * @param request 添加RSS源请求参数
     * @return RSS源响应信息
     * @throws RuntimeException 当RSS源URL无效或已存在时抛出异常
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public FeedResponse addFeed(AddFeedRequest request) {
        log.info("开始添加RSS源，URL: {}", request.getUrl());
        
        try {
            // 检查RSS源是否已存在
            RssFeed existingFeed = rssFeedMapper.selectByUrl(request.getUrl());
            if (existingFeed != null) {
                log.warn("RSS源已存在，URL: {}", request.getUrl());
                throw new RuntimeException("该RSS源已存在");
            }
            
            // 验证并解析RSS源
            RssFeed feedInfo = rssParserService.parseFeedInfo(request.getUrl());
            
            // 使用自定义标题（如果提供）
            if (StringUtils.hasText(request.getCustomTitle())) {
                feedInfo.setTitle(request.getCustomTitle());
            }
            
            // 使用自定义描述（如果提供）
            if (StringUtils.hasText(request.getDescription())) {
                feedInfo.setDescription(request.getDescription());
            }
            
            // 保存RSS源
            rssFeedMapper.insert(feedInfo);
            
            // 异步抓取文章
            try {
                List<Article> articles = rssParserService.parseArticles(feedInfo);
                for (Article article : articles) {
                    // 检查文章是否已存在
                    Article existingArticle = articleMapper.selectByGuid(article.getGuid(), feedInfo.getId());
                    if (existingArticle == null) {
                        articleMapper.insert(article);
                    }
                }
                log.info("成功抓取文章数量: {}", articles.size());
            } catch (Exception e) {
                log.warn("抓取文章失败，但RSS源已添加成功: {}", e.getMessage());
            }
            
            log.info("RSS源添加成功，ID: {}", feedInfo.getId());
            return convertToResponse(feedInfo);
            
        } catch (Exception e) {
            log.error("添加RSS源失败，URL: {}, 错误: {}", request.getUrl(), e.getMessage(), e);
            throw new RuntimeException("添加RSS源失败: " + e.getMessage());
        }
    }

    /**
     * 分页查询RSS源列表
     * 
     * @param page 页码，从1开始
     * @param size 每页大小
     * @return 分页响应结果
     */
    @Override
    public PageResponse<FeedResponse> getFeeds(Integer page, Integer size) {
        log.debug("分页查询RSS源列表，页码: {}, 每页大小: {}", page, size);
        
        try {
            Page<RssFeed> pageParam = new Page<>(page, size);
            Page<RssFeed> result = (Page<RssFeed>) rssFeedMapper.selectFeedPage(pageParam);
            
            List<FeedResponse> responses = result.getRecords().stream()
                    .map(this::convertToResponse)
                    .collect(Collectors.toList());
            
            return PageResponse.of(responses, result.getTotal(), page, size);
            
        } catch (Exception e) {
            log.error("查询RSS源列表失败: {}", e.getMessage(), e);
            throw new RuntimeException("查询RSS源列表失败: " + e.getMessage());
        }
    }

    /**
     * 根据ID获取RSS源详情
     * 
     * @param id RSS源ID
     * @return RSS源响应信息
     * @throws RuntimeException 当RSS源不存在时抛出异常
     */
    @Override
    public FeedResponse getFeedById(Long id) {
        log.debug("根据ID获取RSS源详情，ID: {}", id);
        
        try {
            RssFeed feed = rssFeedMapper.selectById(id);
            if (feed == null || feed.getDeleted() != 0) {
                log.warn("RSS源不存在，ID: {}", id);
                throw new RuntimeException("RSS源不存在");
            }
            
            return convertToResponse(feed);
            
        } catch (Exception e) {
            log.error("获取RSS源详情失败，ID: {}, 错误: {}", id, e.getMessage(), e);
            throw new RuntimeException("获取RSS源详情失败: " + e.getMessage());
        }
    }

    /**
     * 更新RSS源信息
     * 只允许更新标题和描述
     * 
     * @param id          RSS源ID
     * @param title       新标题
     * @param description 新描述
     * @return 更新后的RSS源响应信息
     * @throws RuntimeException 当RSS源不存在时抛出异常
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public FeedResponse updateFeed(Long id, String title, String description) {
        log.info("更新RSS源信息，ID: {}", id);
        
        try {
            RssFeed feed = rssFeedMapper.selectById(id);
            if (feed == null || feed.getDeleted() != 0) {
                log.warn("RSS源不存在，ID: {}", id);
                throw new RuntimeException("RSS源不存在");
            }
            
            LambdaUpdateWrapper<RssFeed> updateWrapper = new LambdaUpdateWrapper<>();
            updateWrapper.eq(RssFeed::getId, id);
            
            if (StringUtils.hasText(title)) {
                updateWrapper.set(RssFeed::getTitle, title);
            }
            
            if (StringUtils.hasText(description)) {
                updateWrapper.set(RssFeed::getDescription, description);
            }
            
            rssFeedMapper.update(null, updateWrapper);
            
            // 重新查询更新后的数据
            RssFeed updatedFeed = rssFeedMapper.selectById(id);
            log.info("RSS源更新成功，ID: {}", id);
            
            return convertToResponse(updatedFeed);
            
        } catch (Exception e) {
            log.error("更新RSS源失败，ID: {}, 错误: {}", id, e.getMessage(), e);
            throw new RuntimeException("更新RSS源失败: " + e.getMessage());
        }
    }

    /**
     * 删除RSS源
     * 逻辑删除，同时删除该RSS源下的所有文章
     * 
     * @param id RSS源ID
     * @throws RuntimeException 当RSS源不存在时抛出异常
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteFeed(Long id) {
        log.info("删除RSS源，ID: {}", id);
        
        try {
            RssFeed feed = rssFeedMapper.selectById(id);
            if (feed == null || feed.getDeleted() != 0) {
                log.warn("RSS源不存在，ID: {}", id);
                throw new RuntimeException("RSS源不存在");
            }
            
            // 逻辑删除RSS源
            rssFeedMapper.deleteById(id);
            
            // 逻辑删除该RSS源下的所有文章
            LambdaUpdateWrapper<Article> articleUpdateWrapper = new LambdaUpdateWrapper<>();
            articleUpdateWrapper.eq(Article::getFeedId, id)
                    .set(Article::getDeleted, true);
            articleMapper.update(null, articleUpdateWrapper);
            
            log.info("RSS源删除成功，ID: {}", id);
            
        } catch (Exception e) {
            log.error("删除RSS源失败，ID: {}, 错误: {}", id, e.getMessage(), e);
            throw new RuntimeException("删除RSS源失败: " + e.getMessage());
        }
    }

    /**
     * 手动同步RSS源
     * 立即抓取指定RSS源的最新文章
     * 
     * @param id RSS源ID
     * @return 同步结果信息
     * @throws RuntimeException 当RSS源不存在或同步失败时抛出异常
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public String syncFeed(Long id) {
        log.info("手动同步RSS源，ID: {}", id);
        
        try {
            RssFeed feed = rssFeedMapper.selectById(id);
            if (feed == null) {
                log.warn("RSS源不存在，ID: {}", id);
                throw new RuntimeException("RSS源不存在");
            }
            
            List<Article> articles = rssParserService.parseArticles(feed);
            int newArticleCount = 0;
            
            for (Article article : articles) {
                // 检查文章是否已存在
                Article existingArticle = articleMapper.selectByGuid(article.getGuid(), feed.getId());
                if (existingArticle == null) {
                    articleMapper.insert(article);
                    newArticleCount++;
                }
            }
            
            // 更新RSS源的最后更新时间
            LambdaUpdateWrapper<RssFeed> updateWrapper = new LambdaUpdateWrapper<>();
            updateWrapper.eq(RssFeed::getId, id)
                    .set(RssFeed::getLastUpdated, LocalDateTime.now());
            rssFeedMapper.update(null, updateWrapper);
            
            String result = String.format("同步完成，新增文章: %d 篇", newArticleCount);
            log.info("RSS源同步成功，ID: {}, {}", id, result);
            
            return result;
            
        } catch (Exception e) {
            log.error("同步RSS源失败，ID: {}, 错误: {}", id, e.getMessage(), e);
            throw new RuntimeException("同步RSS源失败: " + e.getMessage());
        }
    }

    /**
     * 搜索RSS源
     * 根据关键词在标题和描述中进行模糊搜索
     * 
     * @param keyword 搜索关键词
     * @param page    页码，从1开始
     * @param size    每页大小
     * @return 分页响应结果
     */
    @Override
    public PageResponse<FeedResponse> searchFeeds(String keyword, Integer page, Integer size) {
        log.debug("搜索RSS源，关键词: {}, 页码: {}, 每页大小: {}", keyword, page, size);
        
        try {
            Page<RssFeed> pageParam = new Page<>(page, size);
            Page<RssFeed> result = (Page<RssFeed>) rssFeedMapper.searchFeeds(pageParam, keyword);
            
            List<FeedResponse> responses = result.getRecords().stream()
                    .map(this::convertToResponse)
                    .collect(Collectors.toList());
            
            return PageResponse.of(responses, result.getTotal(), page, size);
            
        } catch (Exception e) {
            log.error("搜索RSS源失败，关键词: {}, 错误: {}", keyword, e.getMessage(), e);
            throw new RuntimeException("搜索RSS源失败: " + e.getMessage());
        }
    }

    /**
     * 获取所有活跃的RSS源
     * 用于定时同步任务
     * 
     * @return RSS源实体列表
     */
    @Override
    public List<RssFeed> getAllActiveFeeds() {
        log.debug("获取所有活跃的RSS源");
        
        try {
            return rssFeedMapper.selectAllActiveFeeds();
        } catch (Exception e) {
            log.error("获取活跃RSS源失败: {}", e.getMessage(), e);
            throw new RuntimeException("获取活跃RSS源失败: " + e.getMessage());
        }
    }

    /**
     * 同步所有RSS源
     * 定时任务调用，批量同步所有RSS源的最新文章
     * 
     * @return 同步结果统计信息
     */
    @Override
    public String syncAllFeeds() {
        log.info("开始同步所有RSS源");
        
        try {
            List<RssFeed> feeds = getAllActiveFeeds();
            return rssParserService.batchParseFeeds(feeds);
        } catch (Exception e) {
            log.error("同步所有RSS源失败: {}", e.getMessage(), e);
            throw new RuntimeException("同步所有RSS源失败: " + e.getMessage());
        }
    }

    /**
     * 验证RSS源URL
     * 检查URL是否可访问且为有效的RSS格式
     * 
     * @param url RSS源URL
     * @return 验证结果信息
     */
    @Override
    public String validateFeedUrl(String url) {
        log.debug("验证RSS源URL: {}", url);
        
        try {
            return rssParserService.testConnection(url);
        } catch (Exception e) {
            log.error("验证RSS源URL失败，URL: {}, 错误: {}", url, e.getMessage(), e);
            return "验证失败: " + e.getMessage();
        }
    }

    /**
     * 获取RSS源统计信息
     * 
     * @return 统计信息，包括总数、最近更新数量等
     */
    @Override
    public Object getFeedStatistics() {
        log.debug("获取RSS源统计信息");
        
        try {
            Map<String, Object> statistics = new HashMap<>();
            
            // 总RSS源数量
            Long totalFeeds = rssFeedMapper.countActiveFeeds();
            statistics.put("totalFeeds", totalFeeds);
            
            // 最近更新的RSS源
            List<RssFeed> recentlyUpdated = rssFeedMapper.selectRecentlyUpdatedFeeds(5);
            statistics.put("recentlyUpdatedFeeds", recentlyUpdated.stream()
                    .map(this::convertToResponse)
                    .collect(Collectors.toList()));
            
            // 总未读文章数量
            Long totalUnreadArticles = articleMapper.countUnreadArticles(null);
            statistics.put("totalUnreadArticles", totalUnreadArticles);
            
            return statistics;
            
        } catch (Exception e) {
            log.error("获取RSS源统计信息失败: {}", e.getMessage(), e);
            throw new RuntimeException("获取RSS源统计信息失败: " + e.getMessage());
        }
    }

    /**
     * 将RSS源实体转换为响应DTO
     * 
     * @param feed RSS源实体
     * @return RSS源响应DTO
     */
    private FeedResponse convertToResponse(RssFeed feed) {
        FeedResponse response = new FeedResponse();
        response.setId(feed.getId())
                .setTitle(feed.getTitle())
                .setUrl(feed.getUrl())
                .setDescription(feed.getDescription())
                .setLastUpdated(LocalDateTime.parse(feed.getLastUpdated()))
                .setCreatedAt(LocalDateTime.parse(feed.getCreatedAt()));
        
        // 获取未读文章数量
        try {
            Long unreadCount = articleMapper.countUnreadArticles(feed.getId());
            response.setUnreadCount(unreadCount.intValue());
        } catch (Exception e) {
            log.warn("获取RSS源未读文章数量失败，ID: {}, 错误: {}", feed.getId(), e.getMessage());
            response.setUnreadCount(0);
        }
        
        return response;
    }
}